// 模拟 Vue.js 响应式原理

/*
L2 数据驱动
1. 数据响应式
数据变化，则视图相应变化，避免频繁的Dom操作，提高效率
2. 双向绑定
数据变化，则视图相应变化；同时视图变化，数据也随之改变
3. 数据驱动
开发过程中只需要关注数据本身，不用关心数据是如何渲染到视图
*/

/* L3 数据响应式核心原理-Vue2
Object.defineProperty
浏览器兼容 IE9及以上 */
let data = {
  msg: 'hello~'
}
let vm = {} // 模拟Vue实例
// 数据劫持：当访问或设置vm中成员时，做一些干预操作
Object.defineProperty(vm, 'msg', {
  // 可枚举（可遍历）
  enumerable: true, 
  // 可配置（可用delete删除，可通过defineProperty重新定义）
  configurable: true, 
  // 获取数据时执行 访问器
  get() {
    console.log('get: ', data.msg)
    return data.msg
  },
  // 当设置值时执行 设置器
  set(newValue) {
    console.log('set: ', newValue)
    if(newValue === data.msg) {
      return
    }
    data.msg = newValue
    document.querySelector('#app').textContent = data.msg
  }
})

// 测试
vm.msg = 'Hello~ World~'
setTimeout(() => {
  console.log(vm.msg)
}, 12000)


/* L4 数据响应式核心原理-Vue3
new Proxy()
直接监听对象，而非属性
ES6中新增 IE不支持 性能优于Object.defineProperty */ 
let data = {
  msg: 'hello',
  count: 0
}
// 模拟Vue实例
let vm = new Proxy(data, {
  // 执行代理行为的函数
  // 当访问vm的成员会执行
  get(target, key) {
    console.log('get, key: ', key, target[key])
    return target[key]
  },
  // 当设置vm的成员会执行
  set(target, key, newValue) {
    console.log('set, key: ', key, newValue)
    if(target[key] === newValue) {
      return
    }
    target[key] = newValue
    document.querySelector('#app').textContent = target[key]
  }
})
// 测试
vm.msg = 'HELLO WORLD!'
console.log(vm.msg)


